package com.example.tree;

/**
 * 路径 被定义为一条从树中任意节点出发，沿父节点-子节点连接，达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。
 *  该路径 至少包含一个 节点，且不一定经过根节点。
 *  路径和 是路径中各节点值的总和。
 *
 *  给你一个二叉树的根节点 root ，返回其 最大路径和 。
 *
 *  示例 1：
 * 输入：root = [1,2,3]
 * 输出：6
 * 解释：最优路径是 2 -> 1 -> 3 ，路径和为 2 + 1 + 3 = 6
 *
 *  示例 2：
 * 输入：root = [-10,9,20,null,null,15,7]
 * 输出：42
 * 解释：最优路径是 15 -> 20 -> 7 ，路径和为 15 + 20 + 7 = 42
 *        -10
 *    9         20
 *          15       7
 *
 * 9    9    9
 * 15   15   15
 * 7    7    15
 * 20   42   42
 * -10  34   42
 *
 */
public class Leetcode124_MaxPathSum {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(-10, new TreeNode(9), new TreeNode(20));
        root.right.left = new TreeNode(15);
        root.right.right = new TreeNode(7);
        System.out.println(new Solution().maxPathSum(root));
    }

    static class Solution {
        int maxSum = Integer.MIN_VALUE;
        public int maxPathSum(TreeNode root) {
            maxGain(root);
            return maxSum;
        }

        /**
         * 计算以node为根节点的最大贡献值，也就是在以该节点为根节点的子树中寻找以该节点为起点的一条路径，使得该路径上的节点值之和最大。
         *
         *   非空节点的最大贡献值等于节点值与其子节点中的最大贡献值之和（对于叶节点而言，最大贡献值等于节点值）
         *   空节点的最大贡献值等于 0。
         * @param node
         * @return
         */
        private int maxGain(TreeNode node) {
            if (node == null) return 0; // 空节点的贡献值为0
            // 分别求出左右子树的贡献值
            int leftMaxGain = Math.max(maxGain(node.left), 0); // 如果它的左子树的贡献值小于0，则左子树的贡献值取0
            int rightMaxGain = Math.max(maxGain(node.right), 0); // 如果它的左子树的贡献值小于0，则左子树的贡献值取0

            // 根据左右子树贡献值求出当前节点的最大贡献值
            int curNodeMaxGain = node.val + leftMaxGain + rightMaxGain;

            // 更新最大路径值
            maxSum = Math.max(curNodeMaxGain, maxSum);
//            System.out.println("当前计算的节点是: " + node.val + " 其贡献值为: " + curNodeMaxGain + " 当前的最大路径和为:" + maxSum);
            // 返回节点的最大贡献值
            return node.val + Math.max(leftMaxGain, rightMaxGain);
        }
    }
}
